refactor: simplify terminal.text.width using luasystem 0.7.0 (#204)#206
refactor: simplify terminal.text.width using luasystem 0.7.0 (#204)#206Gitkbc wants to merge 4 commits intolunarmodules:mainfrom
Conversation
Remove per-character width cache and probe a single ambiguous-width character during initialization. Store the measured value globally and delegate width calculation to LuaSystem. Preserve test and test_write APIs for compatibility. Update documentation and rockspec dependency.
src/terminal/text/width.lua
Outdated
| -- re-run to get the total width, since all widths are known now, | ||
| -- but this time do not write the string, just return the width | ||
| return M.test(str) | ||
| M.initialize() |
There was a problem hiding this comment.
I don't think there is any utility left for this function. It was an optimization of the test function, in case you would also want the text to actually show.
src/terminal/text/width.lua
Outdated
| -- character not in the cache will be passed to `system.utf8cwidth` to determine the width. | ||
| --- Character display width helpers. | ||
| -- Uses LuaSystem width calculations with an optional calibrated | ||
| -- ambiguous-width value for terminal-specific behavior. |
There was a problem hiding this comment.
can we leave some more background in the doc comments? the cache part should go, that's clear, but the ambiguous explanation is still useful I think
src/terminal/draw/init.lua
Outdated
|
|
||
|
|
||
| -- returns a string with all box_fmt characters, to pre-load the character width cache | ||
| -- returns a string with all box_fmt characters |
There was a problem hiding this comment.
this has no utility anymore, it was only here to be able to test the default used characters
src/terminal/init.lua
Outdated
| -- @within Initialization | ||
| function M.preload_widths(str) | ||
| text.width.test((str or "") .. M.progress._spinner_fmt_chars() .. M.draw._box_fmt_chars()) | ||
| if str then |
There was a problem hiding this comment.
this function also has no utility anymore
src/terminal/init.lua
Outdated
| sys.setconsoleflags(io.stdin, sys.getconsoleflags(io.stdin) - sys.CIF_PROCESSED_INPUT) | ||
| end | ||
|
|
||
| text.width.initialize(true) |
There was a problem hiding this comment.
testing should be optional. The default can be to test, but the user should be able to skip it. In case of a pipe-out, instead of a terminal, write the test characters would break the output.
src/terminal/text/width.lua
Outdated
| local ambiguous_char = "·" | ||
| local ambiguous_codepoint = utf8.codepoint(ambiguous_char) | ||
|
|
||
| M.ambiguous_width = nil |
There was a problem hiding this comment.
I think it is save to set a default here and document it. Default should be 1.
src/terminal/text/width.lua
Outdated
|
|
||
|
|
||
| local function detect_ambiguous_width() | ||
| local row, col = t.cursor.position.get() |
There was a problem hiding this comment.
should we use istty() here to see if we have a terminal?
src/terminal/text/width.lua
Outdated
| local query = ambiguous_char .. t.cursor.position.query_seq() .. setpos | ||
|
|
||
| t.text.stack.push({ brightness = 0 }) | ||
| local result, err = t.input.query(query, "^\27%[(%d+);(%d+)R$") |
There was a problem hiding this comment.
don't hardcode the sequence, use this library's functions
|
Thanks for the detailed review and the clear pointers, @Tieske. You're right — the initial submission didn’t fully align with the project’s design and conventions. I’ll rework the implementation to address each of your points and ensure it matches the existing architecture and standards. I’ll push a revised version shortly. Appreciate the thorough feedback. |
… calibration (LuaSystem >= 0.7.0)
|
Addressed the requested changes: Please let me know if any further adjustments are needed. |
Tieske
left a comment
There was a problem hiding this comment.
Please review your own PR before submitting, there's quite a few things in here that were obviously wrong.
| local stripped_title = utils.strip_ansi(title) | ||
| local stripped_title_w = text.width.utf8swidth(stripped_title) | ||
| local title_w | ||
| if stripped_title_w <= w_for_title then | ||
| title_w = stripped_title_w | ||
| else | ||
| stripped_title, title_w = utils.truncate_ellipsis(w_for_title, stripped_title, type) | ||
| title = stripped_title | ||
| end | ||
|
|
There was a problem hiding this comment.
shouldn't most of this logic actually go into the truncate_ellipsis function?
|
|
||
|
|
||
| return M | ||
| return M No newline at end of file |
There was a problem hiding this comment.
nitpick; this is an unwanted whitespace change. you can configure you edito probably to honor the settings in .editorconfig to ensure it automatically adheres to the settings
| end | ||
| local sys = require "system" | ||
| local t = require "terminal" | ||
| -- Stored ambiguous width (1 or 2). |
There was a problem hiding this comment.
-- global ambiguous width setting (1 or 2)
| local AMBIGUOUS_WIDTH = 1 -- Default | ||
|
|
||
| return width | ||
| --Getter and setter for ambiguous width, in case users want to manage it themselves or check it after calibration. |
There was a problem hiding this comment.
the doc comments will not properly render in the documentation
There was a problem hiding this comment.
Yeah I will do the required change that is true. I still tried catching it with the git diff but missed it I am truly sorry for this
| function M.get_ambiguous_width() | ||
| return AMBIGUOUS_WIDTH | ||
| end | ||
| -- Manually sets the ambiguous width setting. |
There was a problem hiding this comment.
vertical whitespace isn't aligned with the rest of this code file
| -- @return true | ||
| -- @within Initialization | ||
| function M.initialize(opts) | ||
| function M.initialize(opts) |
There was a problem hiding this comment.
another unnecessary whitespace change. These changes convolute the diff that I'm looking at when reviewing, please don't do this. Also, in this case it even breaks the styling/indentation
There was a problem hiding this comment.
I am sorry for this I will improve it
| end | ||
|
|
||
|
|
||
| function M.isatty() |
There was a problem hiding this comment.
doc comments are missing, this will not show up in the documentation, but it should
| - **`terminal.text.width.test(str)`** – writes characters invisibly, measures cursor movement, and records each character’s width. Call during startup or when you first display unknown glyphs. | ||
| - **`terminal.preload_widths(str)`** – convenience that tests the library’s own box-drawing and progress characters plus any optional `str`. Call once after `terminal.initialize` if you use `terminal.draw` or `terminal.progress`. | ||
| - Use **`terminal.size()`** to get terminal dimensions (rows × columns) so you can fit text to the visible area. | ||
| - **`utf8cwidth(char[, ambiguous_width])`** – returns the display width in columns of a single UTF-8 character (string or codepoint). |
There was a problem hiding this comment.
this is incorrect, the optional parameter doesn't exist
|
|
||
| Ambiguous-width characters default to a width of 1 column. A different | ||
| width (1 or 2) can be specified explicitly via the optional | ||
| `ambiguous_width` parameter. |
There was a problem hiding this comment.
wrong, this should probably mention the calibration option, or the setter that explicitly sets the value
| `test` and `test_write` are preserved for API compatibility. | ||
| - feat(progress): account for ANSI escape sequences in sprite width math. | ||
| Spinner frames and done sprites can now include color/style sequences | ||
| without breaking cursor rewind behavior. |
There was a problem hiding this comment.
no need to add a change entry, there is no release yet
Implements the simplification proposed in #204.
terminal.initialize() (and preload_widths).
Fixes #204.